package xyz.heyaoshare.config.websocket.manager;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * WebSocketSessionManager 管理会话
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 下午1:34
 */
@Slf4j
public class WebSocketSessionManager {

    // 会话映射
    private final ConcurrentMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    // 构造方法私有化，禁止外部创建实例
    private WebSocketSessionManager() {
    }

    // 单例模式
    private static final WebSocketSessionManager INSTANCE = new WebSocketSessionManager();

    /**
     * 获取 WebSocketSessionManager 的单例实例。
     *
     * @return WebSocketSessionManager 的单例实例。
     */
    public static WebSocketSessionManager getInstance() {
        return INSTANCE;
    }

    /**
     * 注册WebSocket会话
     * 此方法用于将WebSocket会话与用户ID关联起来，以便后续可以通过用户ID快速检索会话。
     * 如果之前已经存在相同用户ID的会话，则新的会话将替换旧的会话。
     *
     * @param userId  用户的唯一标识符
     * @param session WebSocket会话对象
     */
    public void registerSession(String userId, WebSocketSession session) {
        sessions.put(userId, session);
    }

    /**
     * 根据用户ID获取WebSocket会话
     *
     * @param userId 用户ID，用于从会话映射中检索对应的WebSocket会话
     * @return 返回与指定用户ID关联的WebSocket会话，如果未找到则返回null
     */
    public WebSocketSession getSession(String userId) {
        return sessions.get(userId);
    }

    /**
     * 返回当前会话的数量。
     *
     * @return 会话的数量，类型为整数。
     */
    public long size() {
        return sessions.size();
    }

    /**
     * 根据用户ID移除会话
     *
     * @param userId 用户ID，用于标识要移除的会话
     */
    public void removeByUserId(String userId) {
        sessions.remove(userId);
    }

    /**
     * 通过会话ID移除会话。
     *
     * @param sessionId 要移除的会话的ID。
     */
    public void removeBySession(String sessionId) {
        sessions.values().removeIf(s -> s.getId().equals(sessionId));
    }

    /**
     * 向指定用户发送WebSocket消息
     * <p>
     * 此方法尝试向指定用户ID的WebSocket会话发送文本消息。首先，通过用户ID获取对应的WebSocket会话。
     * 如果会话存在且处于打开状态，则尝试发送消息，并更新该会话的最后活动时间。
     * 如果发送成功，将记录一条信息日志。如果发送过程中出现异常，将记录一条错误日志。
     * 如果无法获取会话（即用户不在线或会话不存在），则记录一条错误日志。
     *
     * @param userId  接收消息的用户ID
     * @param message 要发送的消息内容
     */
    public void sendMessage(String userId, String message) {
        WebSocketSession session = this.getSession(userId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(message));
                log.info("【WebSocket】发送消息: {} 给userId: {}", message, userId);
            } catch (Exception e) {
                log.error("【WebSocket】发送消息错误: {}", message, e);
            }
        } else {
            log.error("【WebSocket】发送消息失败: userId: {} 不在线 或 不存在", userId);
        }
    }

}